﻿namespace HCore
{
    public struct Vector2
    {
        public Vector2(Fix x, Fix y)
        {
            this.x = x;
            this.y = y;
        }

        public Fix x;

        public Fix y;

        public static Vector2 operator +(Vector2 a, Vector2 b) => new Vector2(a.x + b.x, a.y + b.y);

        public static Vector2 operator -(Vector2 a, Vector2 b) => new Vector2(a.x - b.x, a.y - b.y);

        public static Vector2 operator *(Vector2 a, Vector2 b) => new Vector2(a.x * b.x, a.y * b.y);

        public static Vector2 operator /(Vector2 a, Vector2 b) => new Vector2(a.x / b.x, a.y / b.y);

        public static Vector2 operator -(Vector2 a) => new Vector2(-a.x, -a.y);

        public static Vector2 operator *(Vector2 a, Fix d) => new Vector2(a.x * d, a.y * d);

        public static Vector2 operator *(Fix d, Vector2 a) => new Vector2(a.x * d, a.y * d);

        public static Vector2 operator /(Vector2 a, Fix d) => new Vector2(a.x / d, a.y / d);

        public static bool operator ==(Vector2 lhs, Vector2 rhs)
        {
            return lhs.x == rhs.x && lhs.y == rhs.y;
        }

        public static bool operator !=(Vector2 lhs, Vector2 rhs) => !(lhs == rhs);

        public override int GetHashCode() => this.x.GetHashCode() ^ this.y.GetHashCode() << 2;

        public override bool Equals(object other) => other is Vector2 other1 && this.Equals(other1);

        private static readonly Vector2 zeroVector = new Vector2(Fix.Mix(0), Fix.Mix(0));
        private static readonly Vector2 oneVector = new Vector2(Fix.Mix(1), Fix.Mix(1));
        private static readonly Vector2 upVector = new Vector2(Fix.Mix(0), Fix.Mix(1));
        private static readonly Vector2 downVector = new Vector2(Fix.Mix(0), Fix.Mix(-1));
        private static readonly Vector2 leftVector = new Vector2(Fix.Mix(-1), Fix.Mix(0));
        private static readonly Vector2 rightVector = new Vector2(Fix.Mix(1), Fix.Mix(0));
        public static Vector2 zero => zeroVector;
        public static Vector2 one => oneVector;
        public static Vector2 up => upVector;
        public static Vector2 down => downVector;
        public static Vector2 left => leftVector;
        public static Vector2 right => rightVector;

        public Fix sqrMagnitude => this.x * this.x + this.y * this.y;

        public Fix magnitude => FixMath.Sqrt(sqrMagnitude);

        public override string ToString() => string.Format("({0:F1}, {1:F1})", (object) this.x, (object) this.y);

        public void Normalize()
        {
            Fix magnitude = this.magnitude;
            if (magnitude.Raw > 0)
                this = this / magnitude;
            else
                this = zero;
        }

        public Vector2 normalized
        {
            get
            {
                Vector2 vector2 = new Vector2(this.x, this.y);
                vector2.Normalize();
                return vector2;
            }
        }

        public void Truncate(Fix max)
        {
            if (magnitude > max)
            {
                this = normalized * max;
            }
        }

        public Vector2 Perp() => new Vector2(-y, x);

        public static Fix Distance(Vector2 a, Vector2 b)
        {
            Fix num1 = a.x - b.x;
            Fix num2 = a.y - b.y;
            return FixMath.Sqrt(num1 * num1 + num2 * num2);
        }

        public static Fix Dot(Vector2 lhs, Vector2 rhs) => lhs.x * rhs.x + lhs.y * rhs.y;

        public int Sign(Vector2 v2)
        {
            if (y * v2.x > x * v2.y)
            {
                return -1;
            }
            else
            {
                return 1;
            }
        }
    }
}